package com.xiaoq.shop.repository.impl;

import com.mongodb.WriteConcern;
import com.xiaoq.shop.entity.SimpleLock;
import com.xiaoq.shop.repository.ISimpleLockRepository;
import org.apache.commons.lang3.StringUtils;
import org.mongodb.morphia.Datastore;
import org.mongodb.morphia.query.Query;
import org.mongodb.morphia.query.UpdateOperations;
import org.mongodb.morphia.query.UpdateResults;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

/**
 * Created by chenjh on 2017/12/1.
 */
@Repository
public class SimpleLockRepositoryImpl implements ISimpleLockRepository {

    @Autowired
    private Datastore datastore;

    @Override
    public boolean save(SimpleLock simpleLock) {
        if(simpleLock ==null || StringUtils.isAnyBlank(simpleLock.getId(), simpleLock.getTargetId())){
            return false;
        }
        datastore.save(simpleLock);
        return true;
    }

    @Override
    public boolean lock(SimpleLock simpleLock) {
        if(simpleLock ==null || StringUtils.isBlank(simpleLock.getTargetId())){
            return false;
        }

        long nowMillis = System.currentTimeMillis();
        /*Query<SimpleLock> lockQuery = datastore.createQuery(SimpleLock.class)
                .filter("targetId", simpleLock.getTargetId())
                .filter("lockStatus", 0);*/

        Query<SimpleLock> lockQuery = datastore.createQuery(SimpleLock.class)
                .filter("targetId", simpleLock.getTargetId());
        lockQuery.or(lockQuery.criteria("lockStatus").equal(0),
                lockQuery.criteria("lockExpireTime").lessThan(nowMillis));

        UpdateOperations<SimpleLock> ops = datastore.createUpdateOperations(SimpleLock.class);
        ops.set("updatedAt", nowMillis);
        ops.set("lockStatus", 1);
        if(simpleLock.getLockExpireTime() != null){
            ops.set("lockExpireTime", simpleLock.getLockExpireTime());
        }
        //http://mongodb.github.io/morphia/1.3/javadoc/
        //Updates the first entity found with the operations,
        // if nothing is found insert the update as an entity if "createIfMissing" is true;
        // this is an atomic operation per entity

        //ACKNOWLEDGED: Write operations that use this write concern will wait for acknowledgement from the primary server before returning.
        UpdateResults ur = datastore.updateFirst(lockQuery, ops, false, WriteConcern.ACKNOWLEDGED);
        return ur.getUpdatedExisting();
    }

    @Override
    public boolean releaseLock(SimpleLock simpleLock) {
        if(simpleLock ==null || StringUtils.isBlank(simpleLock.getTargetId())){
            return false;
        }

        Long nowMillis = System.currentTimeMillis();
        Query<SimpleLock> lockQuery = datastore.createQuery(SimpleLock.class)
                .filter("targetId", simpleLock.getTargetId());

        UpdateOperations<SimpleLock> ops = datastore.createUpdateOperations(SimpleLock.class);
        ops.set("updatedAt", nowMillis);
        ops.set("lockStatus", 0);

        datastore.updateFirst(lockQuery, ops);
        return true;
    }
}
